package handler

import (
	"net/http"

	"database/sql"

	"gitee.com/hp-huiw/family-expense-api/internal/service"
	"gitee.com/hp-huiw/my-go-core/util"
	"github.com/gin-gonic/gin"
)

type JoinAccountGroupRequestHandler interface {
	CountReceived(ctx *gin.Context)
	QueryReceiving(ctx *gin.Context)
	Send(ctx *gin.Context)
	Accept(ctx *gin.Context)
	Reject(ctx *gin.Context)
	Delete(ctx *gin.Context)
}

func NewJoinAccountGroupRequestHandler(db *sql.DB) JoinAccountGroupRequestHandler {
	return &joinAccountGroupRequestHandler{
		joinAccountGroupRequestService: service.NewJoinAccountGroupRequestService(db),
	}
}

// Matches /count-received of http get action.
func (h *joinAccountGroupRequestHandler) CountReceived(ctx *gin.Context) {
	c := ctx.Request.Context()
	userID := GetClaims(ctx).UserID
	result, err := h.joinAccountGroupRequestService.CountReceived(c, userID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, map[string]int64{
		"count": result,
	})
}

// Matches /query-receiving of http get action.
func (h *joinAccountGroupRequestHandler) QueryReceiving(ctx *gin.Context) {
	pageSize, err := util.StringToInt64(ctx.Query("pageSize"))

	if err != nil {
		ctx.Error(err)
		return
	}

	pageIndex, err := util.StringToInt64(ctx.Query("pageIndex"))

	if err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	id := GetClaims(ctx).UserID
	result, err := h.joinAccountGroupRequestService.QueryReceiving(c, id, pageSize, pageIndex)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, result)
}

// Matches /send of http post action.
func (h *joinAccountGroupRequestHandler) Send(ctx *gin.Context) {
	var postedData struct {
		ReceiverID string   `json:"receiverId"`
		Roles      []string `json:"roles"`
	}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	receiverID := postedData.ReceiverID
	roles := postedData.Roles

	claims := GetClaims(ctx)
	senderID := claims.UserID
	accountGroupID := claims.AccountGroupID
	err := h.joinAccountGroupRequestService.AddOrUpdate(c, accountGroupID, senderID, receiverID, roles)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendStatusResponse(ctx, http.StatusNoContent)
}

// Matches /accept of http post action.
func (h *joinAccountGroupRequestHandler) Accept(ctx *gin.Context) {
	var postedData struct {
		ID string `json:"id"`
	}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	id := postedData.ID
	receiverID := GetClaims(ctx).UserID
	err := h.joinAccountGroupRequestService.Accept(c, id, receiverID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendStatusResponse(ctx, http.StatusNoContent)
}

// Matches /reject of http post action.
func (h *joinAccountGroupRequestHandler) Reject(ctx *gin.Context) {
	var postedData struct {
		ID string `json:"id"`
	}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	id := postedData.ID
	receiverID := GetClaims(ctx).UserID
	err := h.joinAccountGroupRequestService.Reject(c, id, receiverID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendStatusResponse(ctx, http.StatusNoContent)
}

// Matches /delete of http post action.
func (h *joinAccountGroupRequestHandler) Delete(ctx *gin.Context) {
	// By now rejecting and deleting follow the same logic.
	// But you can distinguish it as you need.
	var postedData struct {
		ID string `json:"id"`
	}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	id := postedData.ID
	receiverID := GetClaims(ctx).UserID
	err := h.joinAccountGroupRequestService.Reject(c, id, receiverID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendStatusResponse(ctx, http.StatusNoContent)
}

// Container of JoinAccountGroupRequestHandler functions.
type joinAccountGroupRequestHandler struct {
	joinAccountGroupRequestService service.JoinAccountGroupRequestService
}
